from datetime import timedelta, datetime

from django.db import transaction
from django.forms import model_to_dict
from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework import status
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework_simplejwt.authentication import JWTAuthentication

from apps.core.pagination import paginated_queryset_response
from apps.notification.models import ProviderNotificationSetting, ProviderReminderSetting, ProviderNotification, \
    ClientNotification
from apps.users.permissions import IsProvider, IsClient


@api_view(('GET', 'PATCH'))
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider])
@transaction.atomic
def notification_setting_api(request):
    if request.method == 'GET':
        queryset = ProviderNotificationSetting.objects.all().first()
        queryset = model_to_dict(queryset, exclude=['created_at', 'updated_at', 'created_by', 'updated_by'])

        return Response(queryset, status=status.HTTP_200_OK)

    if request.method == 'PATCH':
        data = request.data
        settings = ProviderNotificationSetting.objects.all().first()
        for field_name, field_value in data.items():
            if hasattr(ProviderNotificationSetting, field_name):
                setattr(settings, field_name, field_value)

        settings.save()
        settings = model_to_dict(settings, exclude=['created_at', 'updated_at', 'created_by', 'updated_by'])
        return Response(settings, status=status.HTTP_200_OK)


@api_view(('GET', 'PATCH'))
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider])
@transaction.atomic
def reminder_setting_api(request):
    if request.method == 'GET':
        queryset = ProviderReminderSetting.objects.all().first()
        queryset = model_to_dict(queryset, exclude=['created_at', 'updated_at', 'created_by', 'updated_by'])

        return Response(queryset, status=status.HTTP_200_OK)

    if request.method == 'PATCH':
        data = request.data
        settings = ProviderReminderSetting.objects.all().first()
        for field_name, field_value in data.items():
            if hasattr(ProviderReminderSetting, field_name):
                setattr(settings, field_name, field_value)

        settings.save()

        queryset = model_to_dict(settings, exclude=['created_at', 'updated_at', 'created_by', 'updated_by'])

        return Response(queryset, status=status.HTTP_200_OK)


@api_view(('GET', 'POST'))
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider])
@transaction.atomic
def notification_api(request):
    if request.method == 'POST':
        data = request.data
        ProviderNotification.objects.create(**data)
        return Response({"msg": "Notification has added"}, status=status.HTTP_201_CREATED)

    if request.method == 'GET':
        ordering = request.GET.get('ordering', '-created_at')
        today = timezone.localdate(timezone.now())
        limit_day = today - timedelta(days=30)
        query = ProviderNotification.objects.filter(created_at__gte=limit_day).order_by(ordering)
        search = request.GET.get('search', None)
        if search is not None:
            query = query.filter(content__icontain=search)
        notifications = list()
        for notification in query:
            notify = model_to_dict(notification, exclude=['created_at', 'updated_at'])
            notify['datetime'] = datetime.timestamp(notify['datetime'])
            notifications.append(notify)
        return paginated_queryset_response(notifications, request)


@api_view(('GET', 'PATCH', 'DELETE'))
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider])
@transaction.atomic
def notification_id_api(request, notification_id):
    try:
        notification = get_object_or_404(ProviderNotification, id=notification_id)
        if request.method == 'PATCH':
            if request.data.get('read'):
                notification.read = request.data.get('read')
                notification.save()

            return Response({"msg": "Notification has updated"}, status=status.HTTP_200_OK)

        if request.method == 'GET':
            notification = model_to_dict(notification, exclude=['created_at', 'updated_at'])
            return Response(notification, status=status.HTTP_200_OK)

        if request.method == 'DELETE':
            notification.delete()
            return Response({'msg': 'Notification has been deleted'}, status=status.HTTP_204_NO_CONTENT)
    except Exception as e:
        return Response({
            'success': False,
            'message': f'Failed to perform {request.method} operation in notification_id_api because of {str(e)}'
        }, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider])
@transaction.atomic
def mark_all_notification_api(request):
    if request.method == 'GET':
        ProviderNotification.objects.all().update(read=True)

    return Response(201, status=status.HTTP_200_OK)


@api_view(['GET', 'POST'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider | IsClient])
@transaction.atomic
def client_notifications(request):
    if request.method=='GET':
        user = request.user
        today = timezone.now()
        limit_day = today - timedelta(days=30)
        queryset = ClientNotification.objects.filter(
            client_id=user.id,
            created_at__gte=limit_day
        ).order_by('-created_at')

        notifications = []
        for notification in queryset:
            notification_data = {
                'id': notification.id,
                'client': notification.client.id,
                'content': notification.content,
                'datetime': notification.datetime.timestamp() if notification.datetime else None,
                'notification_type': notification.notification_type,
                'read': notification.read
            }
            notifications.append(notification_data)

        return paginated_queryset_response(notifications, request)

    if request.method =='POST':
        user = request.user
        request_data = request.data.copy()
        request_data['provider'] = user.id

        # Ensure datetime is properly formatted
        if 'datetime' in request_data and request_data['datetime'] is not None:
            request_data['datetime'] = datetime.fromtimestamp(int(request_data['datetime']))

        notification = ClientNotification.objects.create(**request_data)
        response_data = {
            'id': notification.id,
            'client': notification.client.id,
            'content': notification.content,
            'datetime': notification.datetime.timestamp() if notification.datetime else None,
            'notification_type': notification.notification_type,
            'read': notification.read
        }
        return Response(response_data, status=201)

@api_view(['GET'])
@authentication_classes([JWTAuthentication])
@permission_classes([IsProvider | IsClient])
@transaction.atomic
def mark_all_notifications(request):
    user = request.user
    ClientNotification.objects.filter(client=user).update(read=True)
    return Response({'message': 'All notifications marked as read.'}, status=200)